-
-
Notifications
You must be signed in to change notification settings - Fork 75
Breaking: Implement parseForESLint() function #412
Conversation
Are you sure |
@j-f1 I was personally just thinking how the name is very unimportant at this stage. The only stakeholders that could possibly care about these particular node names are custom ESLint TypeScript rule authors (I know you are one of them :D) and all of that goes through Having a more situational name like This seemed like the more straightforward starting point, and we could certainly change it in the future if it makes sense to. |
In my understand, this PR adds 2 node types:
Looks good to me. By the way, I think that some cases should be throw syntax errors. For example: const obj = {
a()
}
|
Yes, this is the case in general with the TypeScript compiler (which powers this parser). It is hyper lenient during the parsing phase because it has language services which come later in the pipeline to provide feedback to developers whilst they author TypeScript. Adding our own strictness on top of that would need to come later in a separate PR, but it might be worth doing at some point. |
In what other cases would you get one of these bodyless functions? |
E.g. interface I {
func(): string;
}
declare function myFunc(): boolean;
abstract class C {
abstract foo(): number;
} |
} | ||
); | ||
}); | ||
// it("no-implicit-globals in module", () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just for my own knowledge, why are these tests commented out?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't solved them yet. They need to be solved by a custom Resolver I think, but I didn't want to lose them when I cut the custom resolver out of this PR in favour of this new flag.
It would be fair enough to request I take them out of the PR, but laziness made me want to keep them in as reminders 😄
interface I {
func(): string; // TSMethodSignature
}
declare function myFunc(): boolean; // DeclareFunction
abstract class C {
abstract foo(): number; // TSAbstractMethodDeclaration with FunctionExpression value
} How about |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM aside from one comment.
parser.js
Outdated
@@ -177,6 +185,12 @@ exports.version = require("./package.json").version; | |||
|
|||
exports.parse = parse; | |||
|
|||
exports.parseForESLint = function parseForESLint(code, options) { | |||
options.parseForESLint = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be best to avoid mutating the options object provided by the user. (This was also a problem in eslint/js#329.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In which case I would be forced to change the signature of parse()
to accept an optional third argument. There's no reason that would be an issue, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think it would be an issue.
If you don't want the change to be visible to the public API, you could create a helper function, e.g. parseMaybeForESlint(code, options, internalOptions)
, and have parse
call parseMaybeForESLint(code, options, { isForESLint: false })
and have parseForESLint
call parseMaybeForESLint(code, options, { isForESLint: true })
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about just defensively cloning the options so the user can't see the mutation?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could also do options = Object.assign({}, options, { parseForESLint: true })
. Or insert options = Object.create(options)
before this line.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems strange to have parseForESLint
be mixed with the user-provided options object. For example, if the user added parseForESLint: true
to their options object for some reason, they could cause strange behavior.
@not-an-aardvark PTAL at my latest commit b273fca |
@j-f1 |
This PR implements a parseForESLint() function.
This will be preferred by ESLint, and so we can use it to implement tweaks to the AST which are only required in an ESLint context. The idea is that this will be used only where absolutely necessary.
The most pressing case is that of a method's value (
FunctionExpression
) having no body in some valid situations in TypeScript.For now, the simplest solution is just to namespace the node.type as
TSEmptyBody${node.type}
only in the case that we are parsing for ESLint.Prettier's usage will be completely unaffected because it will continue to use
parse()
.Fixes #400 #389 #402 #253
🎉
Other minor notes:
babel-eslint
issue numbers from that spec file as they were confusingyarn.lock
file